unit uLM2576;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, uBaseCalcForm, StdCtrls, ExtCtrls, ComCtrls;

type
  TfmLM2576 = class(TfmBaseCalcForm)
    edVcc: TLabeledEdit;
    edVout: TLabeledEdit;
    edIloadMin: TLabeledEdit;
    btnCalc: TButton;
    edCOut: TLabeledEdit;
    edIpk: TLabeledEdit;
    edLmin: TLabeledEdit;
    edLIdc: TLabeledEdit;
    cbLmin: TCheckBox;
    edVripple: TLabeledEdit;
    laVcc: TLabel;
    laVout: TLabel;
    laIload: TLabel;
    laCout: TLabel;
    laIpk: TLabel;
    laLmin: TLabel;
    laLIdc: TLabel;
    laVripple: TLabel;
    Bevel1: TBevel;
    edLvms: TLabeledEdit;
    laLvms: TLabel;
    edR: TLabeledEdit;
    laR: TLabel;
    Panel1: TPanel;
    imgMain: TImage;
    GroupBox1: TGroupBox;
    lvList: TListView;
    edILoadMax: TLabeledEdit;
    laILoadCap: TLabel;
    btnRevCalc: TButton;
    Shape1: TShape;
    procedure DoPosFloatKeyPress(Sender: TObject; var Key: Char);
    procedure DoFloatKeyPress(Sender: TObject; var Key: Char);
    procedure btnCalcClick(Sender: TObject);
    procedure cbLminClick(Sender: TObject);
    procedure lvListCompare(Sender: TObject; Item1, Item2: TListItem;
      Data: Integer; var Compare: Integer);
    procedure btnRevCalcClick(Sender: TObject);
  private
    { Private declarations }
    procedure CalcMe;
  protected
    function DoCheckFields: boolean; override;
  public
    { Public declarations }
    class function CalcFriendlyName: string; override;
    class function RunKey: string; override;
    class procedure InvokeCalc; override;
    procedure AfterConstruction; override;
    procedure BeforeDestruction; override;
  end;

var
  fmLM2576: TfmLM2576;

implementation

{$R *.dfm}

uses uFormReg, uLocalization, uENoms, uLM2576Rev;

{ TfmLM2576 }

procedure TfmLM2576.AfterConstruction;
begin
  inherited;
  LoadPictureFromRes(ImgMain.Picture, 'LM2576');
  SetLabels('Vcc', GetString('#global\uin'), GetString('#global\volt'));
  SetLabels('Vout', GetString('#global\uout'), GetString('#global\volt'));
  LocalizeListColumns(lvList);
  laILoadCap.Caption := GetString('#global\iload');
  laILoad.Caption := GetString('#global\amp');
  edILoadMin.EditLabel.Caption := GetString('#global\min');
  edILoadMax.EditLabel.Caption := GetString('#global\max');
  //SetLabels('Iload', GetString('#global\iload'), GetString('#global\amp'));
  SetLabels('Cout', GetLocaleString('cout'), GetString('#global\uf'));
  SetLabels('Ipk', GetLocaleString('ipk'), GetString('#global\amp'));
  SetLabels('Lmin', GetLocaleString('lmin'), GetString('#global\uH'));
  SetLabels('LIdc', GetLocaleString('lidc'), GetString('#global\amp'));
  SetLabels('Vripple', GetLocaleString('vripple'), GetString('#global\mv'));
  SetLabels('lvms', GetLocaleString('lvms'), GetLocaleString('vms'));
  SetLabels('r', GetLocaleString('rripple'), '%');
  btnCalc.Caption := GetLocaleString('docalc');
  btnRevCalc.Caption := GetLocaleString('revcalc');
end;

procedure TfmLM2576.BeforeDestruction;
begin
  inherited;

end;

class function TfmLM2576.CalcFriendlyName: string;
begin
  Result := 'LM2576 Calculator';
end;

class procedure TfmLM2576.InvokeCalc;
begin
  Application.CreateForm(TfmLM2576, fmLM2576);
  inherited;
end;

class function TfmLM2576.RunKey: string;
begin
  Result := 'lm2576';
end;

procedure TfmLM2576.DoPosFloatKeyPress(Sender: TObject; var Key: Char);
begin
  if not (Key in ['0'..'9',chr(VK_BACK),chr(VK_DELETE),DecimalSeparator]) then Key := #0;
end;

procedure TfmLM2576.DoFloatKeyPress(Sender: TObject; var Key: Char);
begin
  if not (Key in ['-','0'..'9',chr(VK_BACK),chr(VK_DELETE),DecimalSeparator]) then Key := #0;
end;

procedure TfmLM2576.CalcMe;
const F = 52000.0;
const T = 1.0/F;
var vIn,vOut,ILmin,ILmax: single;
    Lmin,Dmin,ET,vripple,r,
    LIpk,Ipk,Cout: single;
    r1i: integer;
    r2,avgvo: single;
begin
  vIn := checkField(edVcc);
  vOut := checkField(edVout);
  ILmin := StrToFloatDef(edIloadMin.Text,0);
  if (ILmin<=0) then begin
    Self.HighliteErrorField(edILoadMin);
    exit;
  end;
  ILmax := StrToFloatDef(edIloadMax.Text,0);
  if (ILmax<ILmin) then begin
    ILmax := ILmin;
    edILoadMax.Text := edILoadMin.Text;
  end;

  if not between(StrToFloatDef(edR.Text,0), 50,200, true) then begin
    Self.HighliteErrorField(edR);
    exit;
  end;
  r := checkField(edR)*0.01;

  Dmin := (vOut/vIn); // Minimum duty cycle
  ET := (vin-vout)*(vout/vin)*(1000/(F*1.0e-3)); // volt*microseconds

  if (not cbLmin.Checked) or (StrToFloatDef(edLMin.Text,0)<1) then begin
    //if (r=0) then
    //  Lmin := (vOut/Iload)*(1-Dmin)/(2.0*F) // Minimum inductor value
    //else
      Lmin := ET/(r*ILmin)*1.0e-6;
  end else
    Lmin := StrToFloat(edLmin.Text)*1.0e-6;

  //if (r=0) then
  //  r := ET/((Lmin*1.0e6)*ILmin); // L in uH in this formula

  Ipk := (Dmin*(vin-vout))/(Lmin*F);
  LIpk := 0.5*((vin-vout)/Lmin)*T*(vout/vin)*ILmax;
  Cout := 13300*(vin/(vout*(Lmin*1.0e6)));
  vripple := (1/(Cout*1.0e-6))*((vin-vout)/Lmin)*0.5*(sqr(vout)/sqr(vin))*sqr(T);

  edR.Text := Format('%d', [round(r*100)]);
  edLvms.Text := Format('%.2f', [ET]);
  edIpk.Text := Format('%.2f', [Ipk]);
  edLIdc.Text := Format('%.2f', [LIpk*0.85]);
  edLmin.Text := Format('%.2f', [Lmin*1.0e6]);
  edCout.Text := Format('%.2f', [Cout]);
  edVripple.Text := Format('%.2f', [vripple*1.0e3]);

  // Fill Rx table
  lvList.Items.BeginUpdate;
  try
    lvList.Clear;
    for r1i := 0 to 17 do begin // 1K to 5.1K
      r2 := GetE24(sfE24[r1i]*1.0e3*(Vout/1.23 - 1));
      avgvo := 1.23*(1.0+(r2/(sfE24[r1i]*1.0e3)));
      with lvList.Items.Add do begin
        Caption := Format('%.2fK', [sfE24[r1i]]);
        SubItems.Add(Format('%.2fK', [r2*1.0e-3]));
        SubItems.Add(Format('%.3f V', [avgvo]));
        SubItems.Add(Format('%.2f', [(avgvo-vout)/vout*100.0]));
      end;
    end;
    lvList.AlphaSort;
    RemoveListDupes(lvList);
  finally lvList.Items.EndUpdate; end;
  //lvList.SortType := stData;
end;

procedure TfmLM2576.btnCalcClick(Sender: TObject);
begin
  inherited;
  if not Self.DoCheckFields then exit;
  CalcMe;
end;

function TfmLM2576.DoCheckFields: boolean;
begin
  Result := Self.CheckFieldMore(edVcc,3) and (StrToFloatDef(edVout.Text,0)<>0);
end;

procedure TfmLM2576.cbLminClick(Sender: TObject);
begin
  edLmin.ReadOnly := not cbLmin.Checked;
end;

procedure TfmLM2576.lvListCompare(Sender: TObject; Item1, Item2: TListItem; Data: Integer; var Compare: Integer);
var a,b: single;
begin
  //Compare := CompareText(Item1.SubItems[Item1.SubItems.Count-1], Item2.SubItems[Item1.SubItems.Count-1]);
  a := abs(StrToFloat(Item1.SubItems[Item1.SubItems.Count-1]));
  b := abs(StrToFloat(Item2.SubItems[Item2.SubItems.Count-1]));
  if (a>b) then Compare := 1
  else
  if (b>a) then Compare := -1
  else Compare := 0;
end;

procedure TfmLM2576.btnRevCalcClick(Sender: TObject);
begin
  with TfmLM2576Rev.Create(Self) do try
    ShowModal;
  finally Free; end;
end;

initialization
  RegisterCalc(TfmLM2576);
  
end.
